/**
 * 测试C编译环境
 */


#include <stdio.h>
#include <float.h>

#define IS_TEST_COMPLEX   0
#define IS_TEST_IMAGINARY 0


void test_data_types(void);
void test_integer_data_types(void);
void test_floating_data_types(void);


/**
 * 主函数
 *
 * @param void
 * @return          程序退出状态码
 */
int main(void)
{
    test_data_types();

    return 0;
}

/**
 * 测试数据类型
 *
 * @param void
 * @return void
 */
void test_data_types(void)
{
    printf("# 数据类型\n\n");

    test_integer_data_types();
    test_floating_data_types();
}

/**
 * 测试整数数据类型
 *
 * @param void
 * @return void
 */
void test_integer_data_types(void)
{
    printf("## 整数数据类型\n\n");

    printf("+-----------------------------------------------------------------------------------------------------------+\n");
    printf("| 数据类型                 | 有无符号 | 长度(字节) | 长度(位) | 最小值               | 最大值               |\n");
    printf("+-----------------------------------------------------------------------------------------------------------+\n");

    // _Bool
    printf("| %-24s | %-9s | %-10zu | %-8zu | %-20u | %-20u |\n",
        "_Bool",
        "无",
        sizeof(_Bool),
        sizeof(_Bool) * 8,
        (_Bool)0,
        (_Bool)100
    );

    // char
    printf("| %-24s | %-9s | %-10zu | %-8zu | %-20d | %-20d |\n",
        "char",
        '\xFF' < 0 ? "有" : "无",
        sizeof(char),
        sizeof(char) * 8,
        (char)('\xFF' < 0 ? '\x80' : '\x00'),
        (char)('\xFF' < 0 ? '\x7F' : '\xFF')
    );
    printf("| %-24s | %-9s | %-10zu | %-8zu | %-20d | %-20d |\n",
        "signed char",
        "有",
        sizeof(signed char),
        sizeof(signed char) * 8,
        (signed char)'\x80',
        (signed char)'\x7F'
    );
    printf("| %-24s | %-9s | %-10zu | %-8zu | %-20u | %-20u |\n",
        "unsigned char",
        "无",
        sizeof(unsigned char),
        sizeof(unsigned char) * 8,
        (unsigned char)'\x00',
        (unsigned char)'\xFF'
    );

    // short
    printf("| %-24s | %-9s | %-10zu | %-8zu | %-20hd | %-20hd |\n",
        "[signed] short [int]",
        "有",
        sizeof(short),
        sizeof(short) * 8,
        (short)((short)1 << (sizeof(short) * 8 - 1)),
        (short)(~((short)1 << (sizeof(short) * 8 - 1)))
    );
    printf("| %-24s | %-9s | %-10zu | %-8zu | %-20hu | %-20hu |\n",
        "unsigned short [int]",
        "无",
        sizeof(unsigned short),
        sizeof(unsigned short) * 8,
        (unsigned short)0,
        (unsigned short)(~((unsigned short)0))
    );

    // int
    printf("| %-24s | %-9s | %-10zu | %-8zu | %-20d | %-20d |\n",
        "[signed] int",
        "有",
        sizeof(int),
        sizeof(int) * 8,
        (int)((int)1 << (sizeof(int) * 8 - 1)),
        (int)(~((int)1 << (sizeof(int) * 8 - 1)))
    );
    printf("| %-24s | %-9s | %-10zu | %-8zu | %-20u | %-20u |\n",
        "unsigned [int]",
        "无",
        sizeof(unsigned),
        sizeof(unsigned) * 8,
        (unsigned)0,
        (unsigned)(~((unsigned)0))
    );

    // long
    printf("| %-24s | %-9s | %-10zu | %-8zu | %-20ld | %-20ld |\n",
        "[signed] long [int]",
        "有",
        sizeof(long),
        sizeof(long) * 8,
        (long)((long)1 << (sizeof(long) * 8 - 1)),
        (long)(~((long)1 << (sizeof(long) * 8 - 1)))
    );
    printf("| %-24s | %-9s | %-10zu | %-8zu | %-20lu | %-20lu |\n",
        "unsigned long [int]",
        "无",
        sizeof(unsigned long),
        sizeof(unsigned long) * 8,
        (unsigned long)0,
        (unsigned long)(~((unsigned long)0))
    );

    // long long 
    printf("| %-24s | %-9s | %-10zu | %-8zu | %-20lld | %-20lld |\n",
        "[signed] long long [int]",
        "有",
        sizeof(long long),
        sizeof(long long) * 8,
        (long long)((long long)1 << (sizeof(long long) * 8 - 1)),
        (long long)(~((long long)1 << (sizeof(long long) * 8 - 1)))
    );
    printf("| %-24s | %-9s | %-10zu | %-8zu | %-20llu | %-20llu |\n",
        "unsigned long long [int]",
        "无",
        sizeof(unsigned long long),
        sizeof(unsigned long long) * 8,
        (unsigned long long)0,
        (unsigned long long)(~((unsigned long long)0))
    );

    printf("+-----------------------------------------------------------------------------------------------------------+\n\n");
}

/**
 * 测试浮点数数据类型
 *
 * @param void
 * @return void
 */
void test_floating_data_types(void)
{
    printf("## 浮点数数据类型\n\n");

    printf("+------------------------------------------------------------------------------------------------------------------------+\n");
    printf("| 数据类型               | 长度(字节) | 长度(位) | 负最小值        | 负最大值        | 正最小值        | 正最大值        |\n");
    printf("+------------------------------------------------------------------------------------------------------------------------+\n");

    // float
    printf("| %-22s | %-10zu | %-8zu | %-15e | %-15e | %-15e | %-15e |\n",
        "float",
        sizeof(float),
        sizeof(float) * 8,
        -FLT_MAX,
        -FLT_MIN,
        FLT_MIN,
        FLT_MAX
    );

    // double
    printf("| %-22s | %-10zu | %-8zu | %-15e | %-15e | %-15e | %-15e |\n",
        "double",
        sizeof(double),
        sizeof(double) * 8,
        -DBL_MAX,
        -DBL_MIN,
        DBL_MIN,
        DBL_MAX
    );

    // long double
    printf("| %-22s | %-10zu | %-8zu | %-15Le | %-15Le | %-15Le | %-15Le |\n",
        "long double",
        sizeof(long double),
        sizeof(long double) * 8,
        -LDBL_MAX,
        -LDBL_MIN,
        LDBL_MIN,
        LDBL_MAX
    );

    // 目前，GCC和Clang编译器支持_Complex，但不支持_Imaginary
    // MSVC编译器既不支持_Complex也不支持_Imaginary

    // _Complex
    #if IS_TEST_COMPLEX
    printf("| %-22s | %-10zu | %-8zu | %-15s | %-15s | %-15s | %-15s |\n",
        "float _Complex",
        sizeof(float _Complex),
        sizeof(float _Complex) * 8,
        "", "", "", ""
    );
    printf("| %-22s | %-10zu | %-8zu | %-15s | %-15s | %-15s | %-15s |\n",
        "double _Complex",
        sizeof(double _Complex),
        sizeof(double _Complex) * 8,
        "", "", "", ""
    );
    printf("| %-22s | %-10zu | %-8zu | %-15s | %-15s | %-15s | %-15s |\n",
        "long double _Complex",
        sizeof(long double _Complex),
        sizeof(long double _Complex) * 8,
        "", "", "", ""
    );
    #endif

    // _Imaginary
    #if IS_TEST_IMAGINARY
    printf("| %-22s | %-10zu | %-8zu | %-15s | %-15s | %-15s | %-15s |\n",
        "float _Imaginary",
        sizeof(float _Imaginary),
        sizeof(float _Imaginary) * 8,
        "", "", "", ""
    );
    printf("| %-22s | %-10zu | %-8zu | %-15s | %-15s | %-15s | %-15s |\n",
        "double _Imaginary",
        sizeof(double _Imaginary),
        sizeof(double _Imaginary) * 8,
        "", "", "", ""
    );
    printf("| %-22s | %-10zu | %-8zu | %-15s | %-15s | %-15s | %-15s |\n",
        "long double _Imaginary",
        sizeof(long double _Imaginary),
        sizeof(long double _Imaginary) * 8,
        "", "", "", ""
    );
    #endif

    printf("+------------------------------------------------------------------------------------------------------------------------+\n\n");
}
